package vh.sphynx.runtime.interpreter;

import vh.sphynx.runtime.ExecutionContext;
import vh.sphynx.runtime.SphynxInterpreter;
import vh.sphynx.runtime.VariableStorage;
import vh.sphynx.sphynx.XExpression;
import vh.sphynx.sphynx.XFunctionDeclaration;
import vh.sphynx.sphynx.XReturnStatement;
import vh.sphynx.sphynx.impl.XBlockExpressionImpl;
import vh.sphynx.sphynx.impl.XFunctionDeclarationImpl;
import vh.sphynx.sphynx.impl.XPatternDeclarationImpl;
import vh.sphynx.sphynx.impl.XReturnStatementImpl;

public class XFunctionDeclartationInterpreter {
	
	public static class FunctionReturn  {
		public static final int UNKNOWN = 0;
		public static final int RETURN = 1;
		public static final int BREAK = 2;
		public static final int CONTINUE = 3;
		
		public final Object Result;
		public final int Type;
		
		public FunctionReturn(XReturnStatement stmt, Object result) {
			this.Result = result;
			if (stmt.isReturn()) Type = RETURN;
			else if (stmt.isBreak()) Type = BREAK;
			else if (stmt.isContinue()) Type = CONTINUE;
			else Type = UNKNOWN;
		}
	}
	
	public static Object _evaluate(SphynxInterpreter interpreter, XFunctionDeclarationImpl funcDef, ExecutionContext context) {
		return funcDef;
	}
	
	public static Object _evaluate(SphynxInterpreter interpreter, XPatternDeclarationImpl funcDef, ExecutionContext context) {
		return funcDef;
	}
		
	public static Object _evaluate(SphynxInterpreter interpreter, XBlockExpressionImpl block, ExecutionContext context) {
		Object result = null;
		for(XExpression exp: block.getExpressions()) {			
			result = interpreter.evaluate(exp, context);
			if (result instanceof FunctionReturn)
				break;			
		}
		return result;
	}
	
	public static Object _evaluate(SphynxInterpreter interpreter, XReturnStatementImpl res, ExecutionContext context) {
		return new FunctionReturn(res, res.getValue() != null ? interpreter.resolveValue(res.getValue(), context) : null);
	}
	
	public static Object interpret(SphynxInterpreter interpreter, XFunctionDeclaration funcDef, ExecutionContext context) {
		// parameter passing is done by caller
		context.setExecutingFunction(funcDef);
		Object obj = interpreter.resolveValue(funcDef.getBody(), context);
		if (obj instanceof FunctionReturn)
			obj =  ((FunctionReturn) obj).Type == FunctionReturn.RETURN ? ((FunctionReturn) obj).Result : null;
		return obj;
	}
}
